{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<center>\n",
    "    <p style=\"text-align:center\">\n",
    "        <img alt=\"phoenix logo\" src=\"https://raw.githubusercontent.com/Arize-ai/phoenix-assets/9e6101d95936f4bd4d390efc9ce646dc6937fb2d/images/socal/github-large-banner-phoenix.jpg\" width=\"1000\"/>\n",
    "        <br>\n",
    "        <br>\n",
    "        <a href=\"https://arize.com/docs/phoenix/\">Docs</a>\n",
    "        |\n",
    "        <a href=\"https://github.com/Arize-ai/phoenix\">GitHub</a>\n",
    "        |\n",
    "        <a href=\"https://arize-ai.slack.com/join/shared_invite/zt-2w57bhem8-hq24MB6u7yE_ZF_ilOYSBw#/shared-invite/email\">Community</a>\n",
    "    </p>\n",
    "</center>\n",
    "<h1 align=\"center\">Phoenix Prompts + OpenAI JavaScript SDK Tutorial</h1>\n",
    "\n",
    "Let's see how to get started with using the Phoenix JavaScript SDK to pull prompts from an\n",
    "instance of Phoenix, and then invoke those prompts using the OpenAI JavaScript SDK, all in a Deno Jupyter notebook.\n",
    "\n",
    "> Note: that this example requires an OpenAI API key, and assumes you are running the Phoenix server on localhost:6006."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import * as PhoenixClient from \"npm:@arizeai/phoenix-client\"\n",
    "import OpenAI from \"npm:openai\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's get started by creating a Phoenix client. This is technically optional, as the Phoenix Prompt helper methods will create a client if not provided.\n",
    "\n",
    "However, we will create a client here to show how to configure the client with your Phoenix instance."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "const px = PhoenixClient.createClient({\n",
    "  options: {\n",
    "    baseUrl: \"http://localhost:6006\",\n",
    "    // Uncomment this if you are using a Phoenix instance that requires an API key\n",
    "    // headers: {\n",
    "    //   Authorization: \"bearer xxxxxx\",\n",
    "    // }\n",
    "  }\n",
    "})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, let's setup the OpenAI client. This will require an OpenAI API key setup in your environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "const apiKey = prompt(\"Enter your OpenAI API key:\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "const openai = new OpenAI({ apiKey: apiKey });"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's build a prompt in Phoenix!\n",
    "\n",
    "We will create a prompt called `question-asker` that asks a question and then returns the answer.\n",
    "\n",
    "Let's set up the prompt to use `OpenAI` as the LLM provider, and lets also add a \"variable\" to one of the prompt messages, named `question`.\n",
    "\n",
    "This will allow us to pass in a question to the prompt when we invoke it\n",
    "\n",
    "Once you have a prompt, you can pull it into the notebook using the Phoenix client."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import * as Prompts from \"npm:@arizeai/phoenix-client/prompts\"\n",
    "import { promptVersion } from \"npm:@arizeai/phoenix-client/prompts\"\n",
    "\n",
    "const questionAskerPrompt = await Prompts.createPrompt({\n",
    " name: \"question-asker\",\n",
    " description: \"Asks a question\",\n",
    " version: promptVersion({\n",
    "  description: \"Initial version\",\n",
    "  templateFormat: \"MUSTACHE\",\n",
    "  modelProvider: \"OPENAI\",\n",
    "  modelName: \"gpt-3.5-turbo\",\n",
    "  template: [\n",
    "   {\n",
    "     role: \"user\",\n",
    "     content: \"{{question}}\"\n",
    "   },\n",
    "  ],\n",
    " })\n",
    "})\n",
    "\n",
    "await Deno.jupyter.md`\n",
    "  ### question-asker prompt\n",
    "\n",
    "  \\`\\`\\`json\n",
    "  ${JSON.stringify(questionAskerPrompt, null, 2)}\n",
    "  \\`\\`\\`\n",
    "  `\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// We already have the prompt, but this just proves that we can fetch it from the server as well\n",
    "const questionAskerPrompt = await Prompts.getPrompt({ client: px, prompt: { name: \"question-asker\" } })\n",
    "\n",
    "await Deno.jupyter.md`\n",
    "  ### question-asker prompt\n",
    "\n",
    "  \\`\\`\\`json\n",
    "  ${JSON.stringify(questionAskerPrompt, null, 2)}\n",
    "  \\`\\`\\`\n",
    "  `"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Great! Now we have the contents of the `question-asker` prompt. It's currently in a format that Phoenix understands, so we need to convert it to a format that OpenAI can understand.\n",
    "\n",
    "Luckily, `@arizeai/phoenix-client` has a helper function to convert the prompt to an OpenAI (or another LLM provider) format, and inject variables into the prompt at the same time. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "const openaiPrompt = Prompts.toSDK({ \n",
    "  sdk: \"openai\", \n",
    "  prompt: questionAskerPrompt, \n",
    "  variables: { question: \"How do I write Hello World in Deno?\" } \n",
    "})\n",
    "\n",
    "await Deno.jupyter.md`\n",
    "  ### OpenAI Prompt\n",
    "\n",
    "  \\`\\`\\`json\n",
    "  ${JSON.stringify(openaiPrompt, null, 2)}\n",
    "  \\`\\`\\`\n",
    "`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now have a set of \"invocation parameters\", fully typed and in the format that OpenAI expects.\n",
    "\n",
    "Let's invoke OpenAI with our prompt and get our question answered!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "const response = await openai.chat.completions.create({\n",
    "  ...openaiPrompt,\n",
    "  // you can still override any of the invocation parameters as needed\n",
    "  // for example, you can change the model or stream the response\n",
    "  model: \"gpt-4o-mini\",\n",
    "  stream: false\n",
    "})\n",
    "\n",
    "await Deno.jupyter.md`\n",
    "  ### OpenAI Response\n",
    "\n",
    "  ${response.choices[0].message.content}\n",
    "`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Great! We've successfully invoked OpenAI with our prompt and got a response.\n",
    "\n",
    "You have seen the basic steps to build a prompt in Phoenix, convert it to an OpenAI format, and invoke it.\n",
    "\n",
    "Here are some additional features and capabilities you can explore:\n",
    "\n",
    "- Prompt Versioning / Tagging\n",
    "- Prompt Conversion to other LLM providers"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "typescript"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
